package at.ac.tuwien.mg.bean;

import java.util.Collections;
import java.util.Comparator;
import java.io.Serializable;
import java.util.List;
import java.util.Vector;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;

import at.ac.tuwien.mg.wh.client.Client;
import at.ac.tuwien.mg.wh.dto.ItemDTO;
import at.ac.tuwien.mg.wh.exception.WarehouseException;

@ManagedBean
@SessionScoped
public class User implements Serializable {
	
	private static final long serialVersionUID = -4526289535472829609L;
	private String name;
	private String lastTaskId;
	private String lastProcInstanceId;
	private Offer selectedOffer;
	
	@ManagedProperty(value="#{activiti.processEngine}")
	private ProcessEngine engine;
	
	public User() {
	}

	public List<Task> getAssignedTasks() {
		//System.out.println("User: " + name);
		TaskService taskservice = engine.getTaskService();
		List<Task> tasks;
		try {
			tasks = taskservice.createTaskQuery().taskAssignee(getName()).list();
			/*
			for(Task t :tasks){
				System.out.println("tasks: "+t.getId()+" "+t.getName());
			}
			*/
			return tasks;
		}
		catch(Exception ex) {
			System.out.println("User: " + name + " Message: " + ex.getMessage());
			return null;
		}
	}
	
	/**
	 * Call this as soon as your user task is done and want it to vanish from the inbox.
	 * @return String "inbox".
	 */
	public String finishTask() {
		
		TaskService taskService = engine.getTaskService();
		taskService.complete(lastTaskId);
		return "inbox";		
		
	}
	
	public Order getCurrentOrder() {
		return (Order) engine.getRuntimeService().getVariable(lastProcInstanceId, "currentOrder");
	}
	
	public Vector<Offer> getOffers() {
		
		OfferVector ov = (OfferVector) engine.getRuntimeService().getVariable(lastProcInstanceId, "receivedOffers");
		Vector<Offer> offers = ov.getOffers();
		Comparator<Offer> comparator = new Comparator<Offer>() {
			@Override
			public int compare(Offer o1, Offer o2) {
				int score1 = o1.getRanking();
				int score2 = o2.getRanking();
				if(score1 < score2) {
					return -1;
				}
				else if(score1 == score2) {
					return 0;
				}
				else {
					return 1;
				}
			}
		};		
		Collections.sort(offers, comparator);
		return offers;
				
	}
	
	public void updateCurrentOrder(Order updatedOrder) {
		engine.getRuntimeService().setVariable(lastProcInstanceId, "currentOrder", updatedOrder);
	}
	
	@SuppressWarnings("unchecked")
	public List<ItemDTO> getCurrentBought() {
		return  (List<ItemDTO>) engine.getRuntimeService().getVariable(lastProcInstanceId, "toOrder");
	}
	
	public void updateCurrentBought(List<ItemDTO> toOrder) {
		engine.getRuntimeService().setVariable(lastProcInstanceId, "toOrder", toOrder);
	}
	
	@SuppressWarnings("unchecked")
	public List<ItemDTO> getToHandOut() {
		
		List<ItemDTO> toBook = (List<ItemDTO>) engine.getRuntimeService().getVariable(lastProcInstanceId,"toBook");
		List<ItemDTO> toOrder = (List<ItemDTO>) engine.getRuntimeService().getVariable(lastProcInstanceId,"toOrder");
		Order order = (Order) engine.getRuntimeService().getVariable(lastProcInstanceId,"currentOrder");
		
		List<ItemDTO> originalRequest = null;
	
		try {
			originalRequest = Client.orderToItemList(order);
			
			for(ItemDTO oneFinal: originalRequest){			
					oneFinal.setNumber(0);
	
				if(order.getDeliveryOK()){
					for(ItemDTO oneOrdered: toOrder){
						if(oneOrdered.getCatalogId().equals(oneFinal.getCatalogId())){
							oneFinal.setNumber(oneFinal.getNumber()+oneOrdered.getNumber());
						}
					}	
				}
				
				for(ItemDTO oneBooked: toBook){
					if(oneBooked.getCatalogId().equals(oneFinal.getCatalogId())){
						oneFinal.setNumber(oneFinal.getNumber()+oneBooked.getNumber());
					}
				}	
			}
		
		} catch (WarehouseException e) {	e.printStackTrace();	}
		
		return  originalRequest;
	}
	
	
	public Boolean isOrderApproved() {
		//do stuff to evaluate XOR decision
		Order currentOrder = getCurrentOrder();
		//engine.getProcessEngine().getRuntimeService().getVariable(instanceId, "name");
		return currentOrder.getAcknolwedged();
	}
	
	public String approveOrder() {
		Order changedOrder = getCurrentOrder();
		changedOrder.setAcknolwedged(true);
		updateCurrentOrder(changedOrder);
		return finishTask();
	}
	
	public String denyOrder() {
		Order changedOrder = getCurrentOrder();
		changedOrder.setAcknolwedged(false);
		updateCurrentOrder(changedOrder);
		return finishTask();
	}
	
	public String cancelOrder() {
		Order changedOrder = getCurrentOrder();
		changedOrder.setCanceled(true);
		updateCurrentOrder(changedOrder);
		return finishTask();
	}
	
	public String updateOrder() {
		Order changedOrder = getCurrentOrder();
		changedOrder.setCanceled(false);
		updateCurrentOrder(changedOrder);
		return finishTask();
	}
	
	public String approveDelivery() {
		Order changedOrder = getCurrentOrder();
		changedOrder.setDeliveryOK(true);
		updateCurrentOrder(changedOrder);
		return finishTask();
	}
	
	public String denyDelivery() {
		Order changedOrder = getCurrentOrder();
		changedOrder.setDeliveryOK(false);
		updateCurrentOrder(changedOrder);
		return finishTask();
	}
	
	public String selectOffer() {
		
		engine.getRuntimeService().setVariable(lastProcInstanceId, "selectedOffer", selectedOffer);
		return finishTask();
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public void setEngine(ProcessEngine instance) {
		this.engine = instance;
	}
	
	public String login() {
		//name = FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(context, "#{user.name}", Item.class)
		return "inbox";
	}
	
	public String logout() {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
		session.invalidate();
		return "login";
	}
	
	public String getLastTaskId() {
		return lastTaskId;
	}

	public void setLastTaskId(String lastTaskId) {
		this.lastTaskId = lastTaskId;
	}

	public String getLastProcInstanceId() {
		return lastProcInstanceId;
	}

	public void setLastProcInstanceId(String lastProcInstanceId) {
		this.lastProcInstanceId = lastProcInstanceId;
	}
	
	public Offer getSelectedOffer() {
		return selectedOffer;
	}

	public void setSelectedOffer(Offer selectedOffer) {
		this.selectedOffer = selectedOffer;
	}	

}
